package com.zmn.oms.third.jingdong;

import com.alibaba.fastjson.JSON;
import com.jdwl.open.api.sdk.DefaultJdClient;
import com.jdwl.open.api.sdk.JdClient;
import com.jdwl.open.api.sdk.JdException;
import com.jdwl.open.api.sdk.TokenClient;
import com.jdwl.open.api.sdk.domain.lasim.ImServiceProviderExternalJsfSerivce.*;
import com.jdwl.open.api.sdk.request.JdRequest;
import com.jdwl.open.api.sdk.request.lasim.LasImHfsAppointmentPushLopRequest;
import com.jdwl.open.api.sdk.request.lasim.LasImHfsInstallPushLopRequest;
import com.jdwl.open.api.sdk.request.lasim.LasImHfsOrderSearchLopRequest;
import com.jdwl.open.api.sdk.request.lasim.LasImHfsUninstallPushLopRequest;
import com.jdwl.open.api.sdk.response.AbstractResponse;
import com.jdwl.open.api.sdk.response.lasim.LasImHfsAppointmentPushResponse;
import com.jdwl.open.api.sdk.response.lasim.LasImHfsInstallPushResponse;
import com.jdwl.open.api.sdk.response.lasim.LasImHfsOrderSearchResponse;
import com.jdwl.open.api.sdk.response.lasim.LasImHfsUninstallPushResponse;
import com.zmn.oms.common.enums.ChannelFacade;
import com.zmn.oms.third.core.tracker.FacadeTracker;
import com.zmn.oms.third.jingdong.dto.api.*;
import com.zmn.oms.third.jingdong.handler.JdResponseHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.Date;
import java.util.LinkedList;
import java.util.List;

/**
 * 类描述：
 *
 * @author LiangHailong
 * @date 2019/09/03 18:22
 */
@Slf4j
public final class JingdongApiInvoker {
    private static final String JD_RESPONSE_CODE_SUCCESS = "0";

    private static JdClient CLINET = null;
    private static final int ORDER_CODE_COMPLATE = 81;
    private static final int ORDER_CODE_CANCEL = 133;

    private static final int ORDER_CODE_DUTY_TIME = 100;    // 首次预约
    private static final int ORDER_CODE_DUTY_TIME_AGAIN = 110;  // 再次预约
    private static final int ORDER_CODE_ASSIGN = 200;   // 首次派单
    private static final int ORDER_CODE_ASSIGN_AGAIN = 210; // 再次派单


    /**
     * 使用查询码拉取补偿订单
     * @return PullOrderResult
     */
    public static PullOrderResult pullOrderByQueryCode(String queryCode) {
        return pullOrder(null, queryCode);
    }
    /**
     * 拉取待处理订单(无参)
     * @return PullOrderResult
     */
    public static PullOrderResult pullOrder() {
        return pullOrder(null, null);
    }
    /**
     * 拉取待处理订单
     * @param token
     * @return PullOrderResult
     */
    public static PullOrderResult pullOrder(String token, String queryCode) {
        LasImHfsOrderSearchLopRequest request = new LasImHfsOrderSearchLopRequest();

        JosPullModelDto dto = new JosPullModelDto();
        dto.setVendorCode(JingdongConsts.VENDOR_CODE);
        dto.setToken(JingdongConsts.REQUEST_TOKEN);
        // 存在查询码，则为补偿查询
        if (StringUtils.isNotBlank(queryCode)) {
            dto.setQueryCode(queryCode);
            dto.setOffset(1);
        }
        request.setDto(dto);

        FacadeTracker.FacadeTrackerCore tracker = FacadeTracker.getTracker()
                .dataOut(ChannelFacade.JINGDOND_SERVICE_PLUS)
                .remark("拉取订单");

        PullOrderResult result;
        try {
            LasImHfsOrderSearchResponse response = doRequest(request, token);
            result = JdResponseHandler.parsePullOrderResponse(response);
        } catch (JdException e) {
            String errorMsg = String.format("ErrorCode:[%d]，%s", e.getErrCode(), e.getErrMsg());
            log.error(errorMsg, e);

            result = new PullOrderResult(false);
            result.setMsg(errorMsg);
        }

        tracker.commit();

        return result;
    }

    /**
     * 状态回传(无参)
     * @return SyncOrderResult
     */
    public static SyncOrderResult pushOrderStatus(OrderStatusParams params) {
        return pushOrderStatus(params, null);
    }
    /**
     * 状态回传
     * @param token
     * @return SyncOrderResult
     */
    public static SyncOrderResult pushOrderStatus(OrderStatusParams params, String token) {
        log.info("【{}-API】<状态回传> params：[{}]", JingdongConsts.CHANNEL_NAME, JSON.toJSON(params));
        SyncOrderResult result = new SyncOrderResult(false);

        LasImHfsAppointmentPushLopRequest request = new LasImHfsAppointmentPushLopRequest();

        ImAppointmentStatusDto dto = new ImAppointmentStatusDto();
        dto.setServiceProviderNo(JingdongConsts.VENDOR_CODE);

        dto.setOrderNo(params.getJdOrderId());
        dto.setOperateTime(new Date());

        FacadeTracker.FacadeTrackerCore tracker = FacadeTracker.getTracker()
                .dataOut(ChannelFacade.JINGDOND_SERVICE_PLUS)
                .orderId(params.getOrderId());

        // 确定是预约（改约）还是派工（改派）
        int statusCode = 0;
        String appendStr = null;
        // 同步预约时间
        if (OrderStatusParams.SYNC_TYPE_DUTY_TIME == params.getSyncType()) {
            appendStr = String.format("\"appointmentTimeBegin\":\"%s\",\"appointmentTimeEnd\":\"%s\"",
                    params.getDutyTimeBegin(), params.getDutyTimeEnd());
            statusCode = params.getFirstFlag() ? ORDER_CODE_DUTY_TIME : ORDER_CODE_DUTY_TIME_AGAIN;
            tracker.remark("同步订单状态-%s", params.getFirstFlag() ? "预约时间" : "改约");
        }
        // 同步派单工程师
        else if (OrderStatusParams.SYNC_TYPE_MASTER == params.getSyncType()) {
            appendStr = String.format("\"engineerName\":\"%s\",\"engineerTel\":\"%s\"",
                    params.getMasterName(), params.getMasterPhone());
            statusCode = params.getFirstFlag() ? ORDER_CODE_ASSIGN : ORDER_CODE_ASSIGN_AGAIN;
            tracker.remark("同步订单状态-%s", params.getFirstFlag() ? "派单工程师" : "改派工程师");
        }

        if (statusCode == 0) {
            String paramsStr = JSON.toJSONString(params);
            log.info("【{}-API】<状态回传> 参数错误：[{}]", JingdongConsts.CHANNEL_NAME, paramsStr);
            tracker.remark("同步订单状态失败：参数错误")
                    .reqSummary(paramsStr)
                    .success(false)
                    .commit();

            result.setMsg("参数错误");
            return result;
        }

        StringBuilder detailBuilder = new StringBuilder("[");
        int num = 1;
        for (Long serviceNo : params.getServiceNos()) {
            if (num++ > 1) {
                detailBuilder.append(",");
            }
            detailBuilder.append("{\"serviceNo\":\"").append(serviceNo)
                    .append("\",\"appointmentStatus\":\"").append(statusCode)
                    .append("\",").append(appendStr).append("}");
        }
        detailBuilder.append("]");

        dto.setServiceDetail(detailBuilder.toString());

        request.setDto(dto);

        try {
            LasImHfsAppointmentPushResponse response = doRequest(request, token);
            Result jdResult = response.getResult();
            result.setSuccess(jdResult.getSuccess());
            result.setMsg(jdResult.getErrorMessage());

        } catch (JdException e) {
            String errorMsg = String.format("ErrorCode:[%d]，%s", e.getErrCode(), e.getErrMsg());
            result.setMsg(errorMsg);
            log.error(errorMsg, e);

        } catch (Exception ex) {
            result.setMsg(ex.getMessage());
            log.error(ex.getMessage(), ex);
        }

        tracker.commit();

        return result;
    }

    /**
     * 服务完成(无参)
     * @return SyncOrderResult
     */
    public static SyncOrderResult pushOrderComplete(OrderCompleteParams params) {
        return pushOrderComplete(params, null);
    }
    /**
     * 服务完成
     * @param token
     * @return SyncOrderResult
     */
    public static SyncOrderResult pushOrderComplete(OrderCompleteParams params, String token) {
        log.info("【{}-API】<服务完成> params：[{}]", JingdongConsts.CHANNEL_NAME, JSON.toJSON(params));
        SyncOrderResult result = new SyncOrderResult(false);

        LasImHfsInstallPushLopRequest request = new LasImHfsInstallPushLopRequest();

        ImInstallStatusDto dto = new ImInstallStatusDto();
        dto.setServiceProviderNo(JingdongConsts.VENDOR_CODE);

        dto.setOrderNo(params.getJdOrderId());
        dto.setOperatorName(params.getOperatorName());
        dto.setOperatorTel(params.getOperatorTel());
        dto.setOperateTime(new Date());

        String remark = "";
        if (params.getRemark() != null) {
            remark = String.format(",\"remark\":\"%s\"", params.getRemark());
        }

        StringBuilder detailBuilder = new StringBuilder("[");
        int num = 1;
        for (Long serviceNo : params.getServiceNos()) {
            if (num++ > 1) {
                detailBuilder.append(",");
            }
            detailBuilder.append("{\"serviceNo\":\"").append(serviceNo)
                    .append("\",\"installStatus\":\"").append(ORDER_CODE_COMPLATE).append("\"")
                    .append(remark).append("}");
        }
        detailBuilder.append("]");

        dto.setInstallDetail(detailBuilder.toString());

        request.setDto(dto);

        FacadeTracker.FacadeTrackerCore tracker = FacadeTracker.getTracker()
                .dataOut(ChannelFacade.JINGDOND_SERVICE_PLUS)
                .remark("同步订单完成")
                .orderId(params.getOrderId());

        try {
            LasImHfsInstallPushResponse response = doRequest(request, token);
            Result jdResult = response.getResult();
            result.setSuccess(jdResult.getSuccess());
            result.setMsg(jdResult.getErrorMessage());

        } catch (JdException e) {
            String errorMsg = String.format("ErrorCode:[%d]，%s", e.getErrCode(), e.getErrMsg());
            result.setMsg(errorMsg);
            log.error(errorMsg, e);

        } catch (Exception ex) {
            result.setMsg(ex.getMessage());
            log.error(ex.getMessage(), ex);
        }

        tracker.commit();

        return result;
    }

    /**
     * 订单取消(无参)
     * @return SyncOrderResult
     */
    public static SyncOrderResult pushOrderCancel(OrderCancelParams params) {
        return pushOrderCancel(params, null);
    }
    /**
     * 订单取消
     * @param token
     * @return SyncOrderResult
     */
    public static SyncOrderResult pushOrderCancel(OrderCancelParams params, String token) {
        log.info("【{}-API】<订单取消> params：[{}]", JingdongConsts.CHANNEL_NAME, JSON.toJSON(params));
        SyncOrderResult result = new SyncOrderResult(false);

        LasImHfsUninstallPushLopRequest request = new LasImHfsUninstallPushLopRequest();

        ImUninstallStatusDto dto = new ImUninstallStatusDto();
        dto.setServiceProviderNo(JingdongConsts.VENDOR_CODE);

        dto.setOrderNo(params.getJdOrderId());
        dto.setOperatorName(params.getOperatorName());
        dto.setOperatorTel(params.getOperatorTel());
        dto.setOperateTime(new Date());

        String remark = "";
        if (params.getRemark() != null) {
            remark = String.format(",\"remark\":\"%s\"", params.getRemark());
        }

        StringBuilder detailBuilder = new StringBuilder("[");
        int num = 1;
        for (Long serviceNo : params.getServiceNos()) {
            if (num++ > 1) {
                detailBuilder.append(",");
            }
            detailBuilder.append("{\"serviceNo\":\"").append(serviceNo)
                    .append("\",\"installStatus\":\"").append(ORDER_CODE_CANCEL).append("\"")
                    .append(remark).append("}");
        }
        detailBuilder.append("]");

        dto.setUninstallDetail(detailBuilder.toString());

        request.setDto(dto);

        FacadeTracker.FacadeTrackerCore tracker = FacadeTracker.getTracker()
                .dataOut(ChannelFacade.JINGDOND_SERVICE_PLUS)
                .remark("同步订单取消")
                .orderId(params.getOrderId());

        try {
            LasImHfsUninstallPushResponse response = doRequest(request, token);
            Result jdResult = response.getResult();
            result.setSuccess(jdResult.getSuccess());
            result.setMsg(jdResult.getErrorMessage());

        } catch (JdException e) {
            String errorMsg = String.format("ErrorCode:[%d]，%s", e.getErrCode(), e.getErrMsg());
            result.setMsg(errorMsg);
            log.error(errorMsg, e);

        } catch (Exception ex) {
            result.setMsg(ex.getMessage());
            log.error(ex.getMessage(), ex);
        }

        tracker.commit();

        return result;
    }

    /**
     * 执行API请求
     * @param request
     * @param token
     * @param <T>
     * @return
     * @throws JdException
     */
    private static <T extends AbstractResponse> T doRequest(JdRequest<T> request, String token) throws JdException {
        JdClient client = getClinet(token);

        String requestStr = JSON.toJSONString(request);
        log.info("【{}-API】<请求> [{}]", JingdongConsts.CHANNEL_NAME, requestStr);
        FacadeTracker.FacadeTrackerCore tracker = FacadeTracker.getTracker().reqSummary(requestStr);

        T response = null;
        try {
            response = client.execute(request);

            //获取错误码，如果是token失效，重新刷一下token重新获取token后再调用
            if (TokenClient.isAccessTokenExpired(response.getCode())) {
                String newAccessToken =  _refreshToken();
                if (newAccessToken != null) {
                    //客户端需要存储新的accessToken替换掉失效的accessToken
                    tracker.remark("token失效，刷新token后再次调用，token-old:[%s]; token-new:[%s]", token, newAccessToken);

                    client.setAccessToken(newAccessToken);
                    response = client.execute(request);
                }
            }
        } catch (JdException e) {
            tracker.error(e, "请求失败，ErrorCode:[%d]，%s", e.getErrCode(), e.getErrMsg());
            throw e;
        }

        String responseStr = JSON.toJSONString(response);
        tracker.respSummary(responseStr)
                .success(JD_RESPONSE_CODE_SUCCESS.equals(response.getCode()));
        log.info("【{}-API】<响应> [{}]", JingdongConsts.CHANNEL_NAME, responseStr);

        return response;
    }

    /**
     * 获取Client
     * @return
     */
    private static JdClient getClinet() {
        return getClinet(null);
    }

    /**
     * 获取Client
     * @return
     */
    private static JdClient getClinet(String token) {
        if (token != null) {
            return new DefaultJdClient(JingdongConsts.API_URL, token,
                    JingdongConsts.APPKEY, JingdongConsts.SECRET);
        }

        if (CLINET == null) {
            synchronized (JingdongApiInvoker.class) {
                if (CLINET == null) {
                    JdClient client = new DefaultJdClient(JingdongConsts.API_URL, JingdongTokenManager.getToken(),
                            JingdongConsts.APPKEY, JingdongConsts.SECRET);
                    CLINET = client;
                }
            }
        }

        return CLINET;
    }

    /**
     * 刷新token
     * @return
     */
    private static String _refreshToken() {
        String newAccessToken = new TokenClient(JingdongConsts.TOKEN_URL)
                .getRefreshToken(JingdongTokenManager.getRefreshToken());
        return newAccessToken;
    }

    /**
     * 私有构造器，禁止外部实例化
     */
    private JingdongApiInvoker() {}


    public static void main(String[] args) {
        JingdongConsts.APPKEY = "c94ebab8b73e4a65bf36f3c554f490b2";
        JingdongConsts.SECRET = "d3740af603284e5b9bb5cce34a695d27";
        JingdongConsts.VENDOR_CODE = "0238611947";
        JingdongConsts.REQUEST_TOKEN = "3a4f08fd82f24d66e2e13c3787b8e97d";
        JingdongConsts.API_URL = "https://api.jdwl.com/routerjson";

        String token = "a458157fa3b744069ac09716ae022e07";

        String jdOrderId = "104307896800";
        List<Long> serviceNos = new LinkedList<>();
        serviceNos.add(47310793L);

/*        {
            // 通过查询码补偿查询订单
            String queryCode = "ES_IM_OP157786320079558";
            PullOrderResult result = pullOrder(token, queryCode);
            System.out.println(JSON.toJSONString(result));
        }*/

/*        {
            // 预约时间
            OrderStatusParams params = new OrderStatusParams();
            params.setSyncType(OrderStatusParams.SYNC_TYPE_DUTY_TIME);
            params.setFirstFlag(true);
            params.setJdOrderId(jdOrderId);
            params.setServiceNos(serviceNos);
            params.setDutyTimeBegin("2019-10-10 11:30:00");
            params.setDutyTimeEnd("2019-10-10 12:00:00");

            SyncOrderResult result = pushOrderStatus(params, token);
            log.info("=========================");
            log.info(JSON.toJSONString(result));
            log.info("=========================");
        }*/

/*        {
            // 同步接单工程师
            OrderStatusParams params = new OrderStatusParams();
            params.setSyncType(OrderStatusParams.SYNC_TYPE_MASTER);
            params.setFirstFlag(true);
            params.setJdOrderId(jdOrderId);
            params.setServiceNos(serviceNos);
            params.setMasterName("黄显利");
            params.setMasterPhone("15730252174");
            params.setDutyTimeBegin("19-10-31 12:00:00");
            params.setDutyTimeEnd("19-10-31 13:00:00");

            SyncOrderResult result = pushOrderStatus(params, token);
            log.info("=========================");
            log.info(JSON.toJSONString(result));
            log.info("=========================");
        }*/
/*        {
            // 同步订单完成
            OrderCompleteParams params = new OrderCompleteParams();
            params.setJdOrderId(jdOrderId);
            params.setServiceNos(serviceNos);
            params.setOperatorName("系统");
            params.setOperatorTel("13012345678");
            params.setRemark("同步订单完成");

            SyncOrderResult result = pushOrderComplete(params, token);
            log.info("=========================");
            log.info(JSON.toJSONString(result));
            log.info("=========================");
        }*/
/*
        {
            // 同步订单取消
            OrderCancelParams params = new OrderCancelParams();
            params.setJdOrderId(jdOrderId);
            params.setOperatorName("系统");
            params.setOperatorTel("13012345678");
            params.setRemark("测试同步订单完成");

            SyncOrderResult result = pushOrderCancel(params, token);
            log.info("=========================");
            log.info(JSON.toJSONString(result));
            log.info("=========================");
        }*/
    }
}
